package app.r_teenus.backend.dao;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import app.r_teenus.backend.model.Address;
import app.r_teenus.backend.model.Contact;
import app.r_teenus.backend.model.Employee;
import app.r_teenus.backend.model.Person;
import app.r_teenus.backend.model.UserAccount;


@Repository("personDao")
@Transactional(readOnly = true)
public class PersonDaoImpl extends DefaultDaoImpl implements PersonDao {

	public List<Person> findPersons() {
		List<Person> persons_list = hibernateTemplate.loadAll(Person.class);
		return persons_list;
	}

	/**
	 * Find persons.
	 */
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
	public Person findPersonById(Integer id) {
		hibernateTemplate.getSessionFactory().getCurrentSession().enableFilter("SUBJECT_TYPE").setParameter("SUBJECT_TYPE", 1);
		hibernateTemplate.getSessionFactory().getCurrentSession().enableFilter("SUBJECTATTRIBUTE_TYPE").setParameter("SUBJECTATTRIBUTE_TYPE", 1);
		hibernateTemplate.getSessionFactory().getCurrentSession().enableFilter("CONTACT_TYPE").setParameter("CONTACT_TYPE", 1);
		hibernateTemplate.getSessionFactory().getCurrentSession().enableFilter("CUSTOMER_TYPE").setParameter("CUSTOMER_TYPE", 1);
		Person person = hibernateTemplate.get(Person.class, id);

		SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy");
		if (person.getBirthDate() != null) {
			person.setBirthDateString(df.format(person.getBirthDate()));
		}
		hibernateTemplate.initialize(person.getAddresses());
		hibernateTemplate.initialize(person.getContacts());
		hibernateTemplate.initialize(person.getEmployee());
		return person;
	}

	/**
	 * Saves person.
	 */
	@Transactional(readOnly = false)
	public Person save(Person person) {

		Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		Employee employee = null;
		if (principal instanceof UserDetails) {

			String userName = ((UserDetails) principal).getUsername();
			String userPassword = ((UserDetails) principal).getPassword();
			Employee employeeTmp = new Employee();
			UserAccount userAccount = new UserAccount(userName, userPassword);
			employeeTmp.setUserAccount(new ArrayList<UserAccount>());
			employeeTmp.getUserAccount().add(userAccount);
			employee = (Employee) hibernateTemplate.findByExample(employeeTmp).get(0);
		}

		if (person.getId() != null) {
			person.setUpdated(new Timestamp(new Date().getTime()));
			person.setUpdatedBy(employee);

		} else {
			person.setCreated(new Timestamp(new Date().getTime()));
			person.setCreatedBy(employee);
		}

		hibernateTemplate.saveOrUpdate(person);
		return person;
	}

	/**
	 * Saves address to person.
	 */
	@Transactional(readOnly = false)
	public Person saveAddress(Person person, Address address) {
		address.setAddressType(findAddressTypeById(address.getAddressTypeId()));
		if (address.getId() != null) {
			for (Address addre : person.getAddresses()) {
				if (addre.getId().intValue() == address.getId().intValue()) {
					person.getAddresses().remove(addre);
					break;
				}
			}
		} else {
			address.setSubject(person.getId());
			address.setSubjectType(2);
		}
		person.getAddresses().add(address);
		hibernateTemplate.saveOrUpdate(address);
		return person;
	}

	/**
	 * Saves contact to person. 
	 */
	@Transactional(readOnly = false)
	public Person saveContact(Person person, Contact contact) {
		contact.setContactType(findContactTypeById(contact.getContactTypeId()));
		if (contact.getId() != null) {
			for (Contact cont : person.getContacts()) {
				if (cont.getId().intValue() == contact.getId().intValue()) {
					person.getContacts().remove(cont);
					break;
				}
			}
		} else {
			contact.setSubject(person.getId());
			contact.setSubjectType(1);
		}
		person.getContacts().add(contact);

		hibernateTemplate.saveOrUpdate(contact);
		return person;
	}

	/**
	 * Deletes contact from person.
	 */
	@Transactional(readOnly = false)
	public Person deleteContact(Person person, Integer contactId) {
		for (Contact cont : person.getContacts()) {
			if (cont.getId().intValue() == contactId.intValue()) {
				hibernateTemplate.delete(cont);
				person.getContacts().remove(cont);
				break;
			}
		}
		return person;
	}

	/**
	 * Deletes address from person.
	 */
	@Transactional(readOnly = false)
	public Person deleteAddress(Person person, Integer addressId) {
		for (Address a : person.getAddresses()) {
			if (a.getId().intValue() == addressId.intValue()) {
				hibernateTemplate.delete(a);
				person.getAddresses().remove(a);
				break;
			}
		}
		return person;
	}

	@Transactional(readOnly = false)
	public void delete(Person person) {
		hibernateTemplate.getSessionFactory().getCurrentSession().enableFilter("SUBJECT_TYPE").setParameter("SUBJECT_TYPE", 1);
		hibernateTemplate.getSessionFactory().getCurrentSession().enableFilter("SUBJECTATTRIBUTE_TYPE").setParameter("SUBJECTATTRIBUTE_TYPE", 1);
		hibernateTemplate.getSessionFactory().getCurrentSession().enableFilter("CONTACT_TYPE").setParameter("CONTACT_TYPE", 1);
		hibernateTemplate.getSessionFactory().getCurrentSession().enableFilter("CUSTOMER_TYPE").setParameter("CUSTOMER_TYPE", 1);
		
		person = hibernateTemplate.get(Person.class, person.getId());
		hibernateTemplate.initialize(person.getAddresses());
		hibernateTemplate.initialize(person.getContacts());
		hibernateTemplate.initialize(person.getEmployee());
		hibernateTemplate.delete(person);
	}
}
